<?php
namespace app\common\process;

use think\Request;

class Order extends Info {
    protected $createScene = 'create';
    protected $cartScene = 'cart';
    protected $model = 'jy\\Order';
    //protected $with = ['product'];
    protected $append = ['products', 'tracking'];
    protected $sendProductScene = 'send_product';
    protected $harvestScene = 'harvest';

    public function create($user) {
        $model = $this->model;
        $validate = $this->validate;
        $productSpecsModel = loadModel('tysj\\ProductSpecs');
        $userWalletModel = loadModel('tyyh\\UserWallet');

        $post = loader()->loadAny('request', 'jy\\Order')->create_order();

        try {
            $model->startTrans();
            $productSpecsModel->startTrans();
            $userWalletModel->startTrans();
            if(!$validate->scene($this->createScene)->check($post)) {
                $this->error($validate->getError());
            }

            $login = loadStorage('Login');
            $user = $login->getCurrentUser();

            $number = loadTool('Number');
            $profitSharing = loadEnum('ProfitSharing');
            $snapshotProcess = loadProcess('Snapshot');

            $productSpecs = loadOnly('Model')->find('tysj\\ProductSpecs', $post['psid']);
            $product      = loadOnly('Model')->find('tysj\\Product', $post['pid']);
            $store        = loadOnly('Model')->find('tysj\\Store', $product['sid']);

            if($post['take_type'] == loadEnum('TakeType')->code2key('ziti')) {
                $said = 0;
            } else {
                $said = $snapshotProcess->address($post['aid']);
            }

            $orderModel = loadModel('jy\\Order');
            $order = [
                'uid'              => $user['id'],
                'spreadid'         => $post['spreadid'],
                'said'             => $said,
                'out_trade_no'     => $number->out_trade_no(),
                'transaction_id'   => '',
                'balance'          => $post['balance'],
                'total_fee'        => $productSpecs['price'] * $post['num'],
                'commission'       => $productSpecs['commission'] * $post['num'],
                'refund_fee'       => 0,
                'spbill_create_ip' => $post['ip'],
                'profit_sharing'   => $profitSharing->code2key('fenzhang'),
                'sid'              => $store['id'],
                'sname'            => $store['name'],
                'sub_mch_id'       => $store['sub_mchid'],
                'take_type'        => $post['take_type']
            ];
            $orderModel->save($order);
            $oid = $orderModel->id;
            $this->assign('oid', $oid);

            $snapshot = $snapshotProcess->product($product['id'], $oid);

            $orderProductMdoel = loadModel('jy\\OrderProduct');
            $orderProduct = [
                'oid'        => $oid,
                'sid'        => $store['id'],
                'pid'        => $product['id'],
                'psid'       => $productSpecs['id'],
                'num'        => $post['num'],
                'snapshotid' => $snapshot['id'],
                'fee'        => $productSpecs['price'] * $post['num'],
                'commission' => $productSpecs['commission'] * $post['num']
            ];
            $orderProductMdoel->save($orderProduct);

            $row = loadOnly('Model')->find('tysj\\ProductSpecs', $productSpecs['id']);
            $row->save(['inventory' => $row['inventory'] - $post['num']]);
            loadProcess('UserWallet')->set_balance_ipl($user['id'], $post['balance'] * -1);
            $model->commit();
            $productSpecsModel->commit();
            $userWalletModel->commit();
        } catch(\Exception $e) {
            $model->rollback();
            $productSpecsModel->rollback();
            $userWalletModel->rollback();

            trace($e);
            $this->error($e->getMessage());
        }
        return $this->fetch();
    }

    //从购物车里批量购买商品
    public function cart() {
        $model = $this->model;
        $validate = $this->validate;
        $login = loadStorage('Login');
        $user = $login->getCurrentUser();
        $productSpecsModel = loadModel('tysj\\ProductSpecs');
        $userWalletModel = loadModel('tyyh\\UserWallet');

        $post = loader()->loadAny('request', 'jy\\Order')->cart();

        try {
            $model->startTrans();
            $productSpecsModel->startTrans();
            $userWalletModel->startTrans();
            if(!$validate->scene($this->cartScene)->check($post)) {
                $this->error($validate->getError());
            }

            $data = loadOnly('Cart')->order4store($post['cids']);
            $store = reset($data['sids']);//默认只有一家店
            
            $number = loadTool('Number');
            $profitSharing = loadEnum('ProfitSharing');

            $snapshotProcess = loadProcess('Snapshot');
            if($post['take_type'] == loadEnum('TakeType')->code2key('ziti')) {
                $said = 0;
            } else {
                $said = $snapshotProcess->address($post['aid']);
            }

            $orderModel = loadModel('jy\\Order');
            $order = [
                'uid'              => $user['id'],
                'spreadid'         => $post['spreadid'],
                'said'             => $said,
                'out_trade_no'     => $number->out_trade_no(),
                'transaction_id'   => '',
                'balance'          => $post['balance'],
                'total_fee'        => $data['total_fee'],
                'commission'       => $data['commission'],
                'refund_fee'       => 0,
                'spbill_create_ip' => $post['ip'],
                'profit_sharing'   => $profitSharing->code2key('fenzhang'),
                'sid'              => $store['id'],
                'sname'            => $store['name'],
                'sub_mch_id'       => $store['sub_mchid'],
                'take_type'        => $post['take_type']
            ];
            $orderModel->save($order);
            $oid = $orderModel->id;
            $this->assign('oid', $oid);

            $pids = $data['pids'];
            $snapshots = [];
            foreach($pids as $pid => $v) {
                $snapshot = $snapshotProcess->product_ipl($pid, $oid);
                $snapshots[$pid] = $snapshot['id'];
            }

            $list = $data['list'];
            $psids = $data['psids'];
            $orderProductMdoel = loadModel('jy\\OrderProduct');
            $orderProducts = [];
            foreach($list as $k => $v) {
                $orderProducts[] = [
                    'oid'        => $oid,
                    'sid'        => $v['sid'],
                    'pid'        => $v['pid'],
                    'psid'       => $v['psid'],
                    'num'        => $v['num'],
                    'snapshotid' => $snapshots[$v['pid']],
                    'fee'        => $psids[$v['psid']]['price'] * $v['num'],
                    'commission' => $psids[$v['psid']]['commission'] * $v['num']
                ];

                $row = loadOnly('Model')->find('tysj\\ProductSpecs', $v['psid']);
                $row->save(['inventory' => $row['inventory'] - $v['num']]);
            }
            $orderProductMdoel->isUpdate(false)->saveAll($orderProducts);

            $count = loadModel('tyyh\\UserCart')->whereIn('id', $post['cids'])->delete();
            loadProcess('UserWallet')->set_balance_ipl($user['id'], $post['balance'] * -1);
            $model->commit();
            $productSpecsModel->commit();
            $userWalletModel->commit();
        } catch(\Exception $e) {
            $model->rollback();
            $productSpecsModel->rollback();
            $userWalletModel->rollback();

            trace($e);
            $this->error($e->getMessage());
        }
        return $this->fetch();
    }

    //获取私有列表
    public function private_list($user, $fun = null) {
        return parent::private_list($user, function($model) use ($fun) {
            $post = loader()->loadAny('request', 'jy\\Order')->private_list();

            loader()->loadAny('search', 'jy\\Order')->private_list($model, $post);
            if(is_callable($fun)) {
                $fun($model);
            }
        });
    }

    //获取店铺的订单列表
    public function store_list($user, $fun = null) {
        $post = loader()->loadAny('request', 'jy\\Order')->store_list();
        $model = $this->model;
        loader()->loadAny('search', 'jy\\Order')->store_list($model, $post);
        if(is_callable($fun)) {
            $fun($model);
        }
        if($post['limit']) {
            $list = $model->paginate($post['limit']);
        } else {
            $list = $model->select();
        }
        $this->assign('list', $list);
        return $this->fetch();
    }

    //根据订单编号获取订单详情
    public function preview_look4out_trade_no($fun = null) {
        $validate = $this->validate;
        $post = loader()->loadAny('request', 'jy\\Order')->preview_look4out_trade_no();
        if (!$validate->scene('preview_look4out_trade_no')->check($post)) {
            $this->error($validate->getError());
        }
        $model = $this->model;
        $model->with($this->with);
        if(is_callable($fun)) {
            $fun($model);
        }
        $row = $model->where(['out_trade_no' => $post['out_trade_no']])->find();
        if($row) {
            $row = $row->append($this->append);
        }
        $this->assign('out_trade_no', $post['out_trade_no']);
        $this->assign($this->row, $row);
        return $this->fetch();
    }

    //私有查看全部信息，需要验证
    public function preview_look_store($user, $fun = null) {
        $validate = $this->validate;
        $post = loader()->loadAny('request', 'jy\\Order')->get_private_id();
        if (!$validate->scene('store')->check($post)) {
            $this->error($validate->getError());
        }
        return $this->preview_look_ipl($post['id'], $fun);
    }

    //发货
    public function send_product($user) {
        $validate = $this->validate;
        $model = $this->model;

        $statusEnum  = loadEnum('OrderStatus');
        $post = loader()->loadAny('request', 'jy\\Order')->send_product();
        $post['uid'] = $user['id'];

        if(!$validate->scene($this->sendProductScene)->check($post)) {
            $this->error($validate->getError());
        }
        try {
            $model->startTrans();
            $order = $model->find($post['id']);
            $order->status = $statusEnum->code2key('daishouhuo');
            $order->delivery_time = time();
            $order->save();

            loadModel('jy\\OrderLogistics')->save([
                'oid'       => $post['id'],
                'tracking'  => $post['tracking']
            ]);
            if(!is_test()) {
                $this->wechat_send_product($order, $post);    
            }
            $model->commit();
        } catch(\Exception $e) {
            $model->rollback();
            $this->error($e->getMessage());
        }
        return $post;
    }

    //通知微信小程序订单发货管理系统发货
    public function wechat_send_product($order, $post) {
        $app = loadTool('Wechat')->miniprogram();
        $openid = loadOnly('tyyh\\UserOpenid')->get_openid($order['route'], $order['uid']);

        $tracking = $post['tracking'];
        $logistics_type = 2;
        if($tracking) {
            $logistics_type = 1;
        }

        $express_company = '其它快递';
        preg_match_all('/([A-Z]+)(?=\d)/', $tracking , $matches);
        if(isset($matches[0]) && isset($matches[0][0]) && in_array($matches[0][0], ["J", "DJ"])) {
            $express_company = '急送帮';
        }

        $params= [
            "order_key" => [
                "order_number_type" => "2",
                "transaction_id" => $order['transaction_id'] // 支付流水号
            ],
            "logistics_type" => $logistics_type,
            "delivery_mode"  => 1,
            "shipping_list"  => [
                [
                    "item_desc"       => "支付编号--" . $order['out_trade_no'],
                    "tracking_no"     => $tracking,
                    "express_company" => $express_company
                ]
            ],
            "upload_time" => date('Y-m-d\TH:i:sP'),
            "payer" => [
                "openid" => $openid// 用户openid
            ]
        ];

        $result = $app->shipping->uploadShippingInfo($params);
        if ($result['errcode'] != 0) {
            // 与微信服务器通信失败（如网络错误、参数格式错误）
            throw new \Exception($result['errmsg']);
        }
        return true;
    }

    //收货
    public function harvest($user) {
        $validate = $this->validate;
        $model = $this->model;

        $statusEnum  = loadEnum('OrderStatus');
        $post = input('post.');
        $post['uid'] = $user['id'];

        if(!$validate->scene($this->harvestScene)->check($post)) {
            $this->error($validate->getError());
        }
        return $model->save(['status' => $statusEnum->code2key('yiwancheng'), 'receive_time' => time()], ['id' => $post['id']]);
    }

    //修改收货地址
    public function set_address($user) {
        $validate = $this->validate;
        $model = $this->model;

        $post = input('post.');
        $post['uid'] = $user['id'];

        if(!$validate->scene('set_address')->check($post)) {
            $this->error($validate->getError());
        }
        
        $order = loadOnly('model')->find('jy\\Order', $post['id']);
        $snapshotProcess = loadProcess('Snapshot');
        $said = $snapshotProcess->address($post['aid']);
        $snapshotProcess->del_address($order['said']);
        return $order->save(['said' => $said]);
    }

    //取消订单
    public function reverse($user) {
        $validate = $this->validate;
        $model = $this->model;
        $specsModel = loadModel('tysj\\ProductSpecs');
        $userWalletModel = loadModel('tyyh\\UserWallet');

        $post = input('post.');
        $post['uid'] = $user['id'];

        if(!$validate->scene('reverse')->check($post)) {
            $this->error($validate->getError());
        }
        try {
            $model->startTrans();
            $specsModel->startTrans();
            $userWalletModel->startTrans();
            $this->reverse_ipl($post['id']);
            $model->commit();
            $specsModel->commit();
            $userWalletModel->commit();
        } catch(\Exception $e) {
            $model->rollback();
            $specsModel->rollback();
            $userWalletModel->rollback();
            trace($e);
            return $this->error($e->getMessage());
        }
        return $this->success('订单取消成功');
    }

    //内部直接取消订单，非安全不要主动调用
    public function reverse_ipl($id) {
        $redis = loader()->loadAny('redis', 'redis');
        
        $specsModel = loadModel('tysj\\ProductSpecs');

        $order = loadOnly('Model')->find('jy\\Order', $id);
        $products = loadModel('jy\\OrderProduct')->where('oid', $id)->select();
        $statusEnum = loadEnum('OrderStatus');
        $result = $order->save(['status' => $statusEnum->code2key('guanbidingdan')]);
        if($order['balance'] > 0) {
            loadProcess('UserWallet')->set_balance_ipl($order['uid'], $order['balance']);
        }
        foreach($products as $k => $v) {
            $row = $specsModel->find($v['psid']);
            $row->inventory = ['inc', $v['num']];
            $row->save();
        }

        $cache = $redis->getArray('pay_order_' . $id);
        if($cache) {
            $outTradeNo = $order['out_trade_no'];
            //$app = loadTool('Wechat')->payment();
            //$app->reverse->byOutTradeNumber($outTradeNo);
            $redis->set('pay_order_' . $id, '');
        }
            
    }

    //处理订单超时
    public function order_timeout() {
        $statusEnum = loadEnum('OrderStatus');
        $model = $this->model;
        $specsModel = loadModel('tysj\\ProductSpecs');
        $userWalletModel = loadModel('tyyh\\UserWallet');

        try {
            $model->startTrans();
            $specsModel->startTrans();
            $userWalletModel->startTrans();
            

            $time = time() - 900;
            $orders = $model->where('status', $statusEnum->code2key('daizhifu'))->where('createtime', '<', $time)->select();
            foreach($orders as $k => $order) {
                $this->reverse_ipl($order['id']);
            }

            $model->commit();
            $specsModel->commit();
            $userWalletModel->commit();
        } catch(\Exception $e) {
            $model->rollback();
            $productSpecsModel->rollback();
            $userWalletModel->rollback();

            trace($e);
            $this->error($e->getMessage());
        }

        $result = ['list' => $orders];

        return $result;
    }

    //处理自动收货
    public function order_automatic_delivery() {
        $statusEnum = loadEnum('OrderStatus');
        $model = $this->model;
        $time = time() - 7 * 24 * 3600;
        $orders = $model->where('status', $statusEnum->code2key('daishouhuo'))->where('delivery_time', '<', $time)->select();
        foreach($orders as $k => $order) {
            $order->status = $statusEnum->code2key('yiwancheng');
            $order->save();  
        }
        return ['list' => $orders];
    }

    //用户申请退款
    public function refund($user) {
        $validate = $this->validate;
        $model = $this->model;

        $post = input('post.');
        $post['uid'] = $user['id'];

        if(!$validate->scene('refund')->check($post)) {
            $this->error($validate->getError());
        }

        try {
            $model->startTrans();
            $this->refund_ipl($post);
            $model->commit();
        } catch (\Exception $e) {
            $model->rollback();
            $this->error($e->getMessage());
            throw $e;
        }
    }

    public function refund_ipl($data) {
        $id = $data['id'];
        $number = loadTool('Number');
        $only = loadOnly('Model');
        $logTypeEnum = loadEnum('OrderRefundLogType');
        $order = $only->find('jy\\Order', $id);

        $orderRefundModel = $only->getModel('jy\\OrderRefund');
        $orderRefundLogModel = $only->getModel('jy\\OrderRefundLog');
        $orderRefundLogModel = $only->getModel('jy\\OrderRefundProduct');

        $refund = [
            'oid'                 => $id,
            'refund_out_trade_no' => $number->refund_out_trade_no(),
            'fee'                 => $post['fee']
        ];
        $orderRefundLogModel->save($refund);

        $log = [
            'type'      => $logTypeEnum->code2key('yonghucaozuo'),
            'relatedid' => $data['uid'],
            'name'      => '用户申请退款',
            'remark'    => isset($post['remark']) ? $post['remark'] : ''
        ];
        $orderRefundLog->save($log);
        $this->refund_by_transaction_id($id, $post['fee']);
    }

    //退款
    public function refund_by_transaction_id($id) {
        $order = loadOnly('Model')->find('jy\\Order', $id);
        $number = loadTool('Number');
        //$app->refund->byTransactionId(string $transactionId, string $refundNumber, int $totalFee, int $refundFee, array $config = []);
    }

    //设置订单消息跳转路径
    public function set_msg_jump_path_ipl($path) {
        $app = loadTool('Wechat')->miniprogram('miniprogram2');
        $result = $app->shipping->setMsgJumpPath($path);
        if($result['errcode'] != 0) {
            throw new \Exception($result['errmsg']);
        }
        return true;
    }
}
